﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Security.Principal;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Utilities;
using File = Microsoft.SharePoint.Client.File;

namespace SPMonsterClone
{
    /// <summary>
    /// It is based
    /// http://dotnetbyexample.blogspot.kr/2011/03/sharepoint-client-object-model-sites.html
    /// </summary>
    public class SharepointHelper
    {
        private ClientContext clientContext;
        private Web rootWeb;

        public SharepointHelper(string url, string username, string password)
        {
            clientContext = new ClientContext(url);
            var credentials = new NetworkCredential(username, password, "domain");
            clientContext.Credentials = credentials;
            rootWeb = clientContext.Web;
            clientContext.Load(rootWeb);
        }

        public void CreateSite(string siteDescription, string siteTitle, string siteUrl)
        {
            rootWeb = rootWeb.Webs.Add(new WebCreationInformation
            {
                Description = siteDescription,
                Title = siteTitle,
                Url = siteUrl,
                UseSamePermissionsAsParentSite = false
            });
            clientContext.ExecuteQuery();
        }

        public Web GetWebByTitle(string siteTitle)
        {
            var query = clientContext.LoadQuery(
              rootWeb.Webs.Where(p => p.Title == siteTitle));
            clientContext.ExecuteQuery();
            return query.FirstOrDefault();
        }

        private RoleDefinition GetRole(string siteTitle, RoleType rType)
        {
            var web = GetWebByTitle(siteTitle);
            if (web != null)
            {
                var roleDefs = web.RoleDefinitions;
                var query = clientContext.LoadQuery(
                    roleDefs.Where(p => p.RoleTypeKind == rType));
                clientContext.ExecuteQuery();
                return query.FirstOrDefault();
            }
            return null;
        }

        public Principal GetPrincipal(string name)
        {
            if (rootWeb != null)
            {
                try
                {
                    var principal = rootWeb.EnsureUser(name);
                    clientContext.Load(principal);
                    clientContext.ExecuteQuery();
                    if (principal != null)
                    {
                        return principal;
                    }
                }
                catch (ServerException) { }
            }
            return null;
        }

        public List GetDocumentLibrary(string siteTitle, string libraryName)
        {
            var web = GetWebByTitle(siteTitle);
            if (web != null)
            {
                var query = clientContext.LoadQuery(
                     web.Lists.Where(p => p.Title == libraryName));
                clientContext.ExecuteQuery();
                return query.FirstOrDefault();
            }
            return null;
        }

        public ListTemplate GetDocumentLibraryTemplate(Web web, string name)
        {
            ListTemplateCollection ltc = web.ListTemplates;
            var listTemplates = clientContext.LoadQuery(
              ltc.Where(p => p.InternalName == name));
            clientContext.Load(ltc);
            clientContext.ExecuteQuery();
            return listTemplates.FirstOrDefault();
        }

        public bool CreateDocumentLibrary(string siteTitle, string libraryName,
                                  string libraryDescription, string userGroup)
        {
            var web = GetWebByTitle(siteTitle);
            if (web != null)
            {
                // First load all the list
                var lists = web.Lists;
                clientContext.Load(lists);
                clientContext.ExecuteQuery();

                // Create new lib based upon the doclib template
                var newList = lists.Add(new ListCreationInformation
                {
                    Title = libraryName,
                    Description = libraryDescription,
                    TemplateType =
                      GetDocumentLibraryTemplate(web, "doclib").ListTemplateTypeKind
                });
                clientContext.ExecuteQuery();

                // Override default permission inheritance
                newList.BreakRoleInheritance(true, false);
                // Get principal for usergroup and the contributor role
                var principal = GetPrincipal(userGroup);
                var role = GetRole(siteTitle, RoleType.Contributor);

                // Add the role to the collection.
                var collRdb = new RoleDefinitionBindingCollection(clientContext) { role };
                var collRoleAssign = newList.RoleAssignments;
                collRoleAssign.Add(principal, collRdb);

                clientContext.ExecuteQuery();

                return true;
            }
            return false;
        }

        public void CreateFolder(string siteTitle, string libraryName, string folder)
        {
            var list = GetDocumentLibrary(siteTitle, libraryName);
            if (list != null)
            {
                var folders = list.RootFolder.Folders;
                clientContext.Load(folders);
                clientContext.ExecuteQuery();
                var newFolder = folders.Add(folder);
                clientContext.ExecuteQuery();
            }
        }

        public void UploadDocument(string siteTitle, string libraryName, string fileName)
        {
            var web = GetWebByTitle(siteTitle);
            var fInfo = new FileInfo(fileName);
            var targetLocation = string.Format("{0}/{1}/{2}", web.ServerRelativeUrl,
               libraryName, fInfo.Name);

            using (var fs = new FileStream(fileName, FileMode.Open))
            {
                File.SaveBinaryDirect(clientContext, targetLocation, fs, true);
            }
        }

        public void DownloadDocument(string siteTitle, string libraryName,
                             string fileName)
        {
            var web = GetWebByTitle(siteTitle);
            var fInfo = new FileInfo(fileName);

            var source = string.Format("{0}/{1}/{2}", web.ServerRelativeUrl,
                                                      libraryName, fInfo.Name);
            var spFileInfo = File.OpenBinaryDirect(clientContext, source);
            using (var fs = new FileStream(fileName, FileMode.OpenOrCreate))
            {
                spFileInfo.Stream.CopyTo(fs);
            }
        }

        public List<File> ListFiles(string siteTitle, string libraryName)
        {
            var list = GetDocumentLibrary(siteTitle, libraryName);
            var files = list.RootFolder.Files;
            clientContext.Load(files);
            clientContext.ExecuteQuery();
            return files.ToList();
        }

        public List<Folder> ListFolders(string siteTitle, string libraryName)
        {
            var list = GetDocumentLibrary(siteTitle, libraryName);
            var folders = list.RootFolder.Folders;
            clientContext.Load(folders);
            clientContext.ExecuteQuery();
            return folders.ToList();
        }
    }
}
